package com.laogao.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.laogao.entity.Goods;
import com.laogao.mapper.GoodsMapper;
import com.laogao.redis.RedisCache;
import com.laogao.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;

import java.util.concurrent.TimeUnit;

@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private RedisCache redisCache;
    String GOODS_KEY = "goodsKey:";

    @Override
    public Goods getGoodsIdById(String goodsId) {
        Goods cacheGoods = (Goods) redisCache.getCacheObject(GOODS_KEY + goodsId);
        if (cacheGoods != null) {
            return cacheGoods;
        }
        Goods goods = goodsMapper.selectById(goodsId);
        Assert.notNull(goods, "查询为空!");
        redisCache.setCacheObject(GOODS_KEY + goodsId, goods);
        return goods;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateGoods(Goods goods) {
        Assert.notNull(goods.getGoodsId(), "参数goodsId为空!");
        goodsMapper.updateById(goods);
        redisCache.deleteObject(GOODS_KEY + goods.getGoodsId());
        return 1;
    }

    @Autowired
    private TransactionTemplate transactionTemplate;

    public Goods getGoodsIdByIdV2(String goodsId) {
        // Step 1: 查询缓存
        Goods cacheGoods = redisCache.getCacheObject(GOODS_KEY + goodsId);
        if (cacheGoods != null) {
            return cacheGoods;
        }
        // Step 2: 双重检查锁定（分布式系统需替换为 Redis 分布式锁）
        synchronized (this) {
            cacheGoods = redisCache.getCacheObject(GOODS_KEY + goodsId);
            if (cacheGoods != null) {
                return cacheGoods;
            }
            // Step 3: 开启事务
            return transactionTemplate.execute(status -> {
                try {
                    // Step 4: 悲观锁查询（需确保 goodsId 字段有索引）
                    Goods goods = goodsMapper.getGoodsByIdForUpdate(goodsId);
                    Assert.notNull(goods, "商品不存在");
                    // Step 5: 事务提交后更新缓存（避免脏数据）
                    TransactionSynchronizationManager.registerSynchronization(
                            new TransactionSynchronization() {
                                @Override
                                public void afterCommit() {
                                    redisCache.setCacheObject(GOODS_KEY + goodsId, goods, 30, TimeUnit.MINUTES);
                                }
                            }
                    );
                    return goods;
                } catch (Exception e) {
                    // 异常回滚时清理缓存（防止写入无效数据）
                    redisCache.deleteObject(GOODS_KEY + goodsId);
                    status.setRollbackOnly();
                    throw new RuntimeException("商品查询失败: " + e.getMessage(), e);
                }
            });
        }
    }

    @Override
    public int updateGoodsV2(Goods goods) {
        //Step1: 开启事务
        return transactionTemplate.execute(status -> {
            try {
                // Step2: 更新数据库并获取影响行数
                int rows = goodsMapper.updateById(goods);
                // Step3: 通过悲观锁二次确认数据状态
                Goods lockedGoods = goodsMapper.getGoodsByIdForUpdate(goods.getGoodsId());
                Assert.notNull(lockedGoods, "商品不存在或已被删除");
                // Step4: 事务提交后删除缓存
                TransactionSynchronizationManager.registerSynchronization(
                        new TransactionSynchronization() {
                            @Override
                            public void afterCommit() {
                                redisCache.deleteObject(GOODS_KEY + goods.getGoodsId());
                            }
                        }
                );
                //返回实际影响行数
                return rows;
            } catch (Exception e) {
                redisCache.deleteObject(GOODS_KEY + goods.getGoodsId());
                throw new RuntimeException("商品更新失败: " + e.getMessage(), e);
            }
        });
    }
}